from __future__ import absolute_import

import json
from functools import wraps
from typing import Dict, Any

import jwt
import tornado.web
from tornado.escape import xhtml_escape as xss_escape

from common import session
from models import AdminLog


def authorize(power: str, log: bool = False, verify_token=False):
    def decorator(func):
        def func_verify_token(handler):
            ret = {"success": True, "msg": "", "payload": {}}
            # JWT 认证
            auth = handler.request.headers.get('Authorization')
            if not auth:
                ret.update({"success": False, "msg": "Missing authorization"})
                return ret
            parts = auth.split()
            if parts[0].lower() != 'bearer' or len(parts) == 1 or len(parts) > 2:
                ret.update({"success": False, "msg": "invalid header authorization"})
                return ret
            token = parts[1]
            payload, error = handler.get_payload(token=token)
            if error:
                ret.update({"success": False, "msg": error})
                return ret
            ret['payload'] = payload
            return ret

        # @tornado.web.authenticated
        @wraps(func)
        def wrapper(*args, **kwargs):
            handler = args[0]
            request = handler.request

            # jwt token verify >>>
            # 不验证token的情况下, 需要验证用户登录
            if not verify_token and not handler.current_user:
                return handler.jsonify(success=False, msg="需要登录!")
            if verify_token:
                ret_verify = func_verify_token(handler)
                if not ret_verify.get('success'):
                    return handler.jsonify(**ret_verify)
                # print(ret_verify.get('payload'))
                login_user_id = ret_verify.get('payload', {}).get('user_id', '')
                handler.jwt_login_user_id = str(login_user_id)
            # JWT <<<

            user_powers = handler.get_current_user_power()
            if not power in user_powers:
                if log:
                    handler.admin_log(request=request, uid=handler.get_current_user(), is_access=False)
                if request.method == 'GET':
                    raise tornado.web.HTTPError(403)
                else:
                    return handler.jsonify(success=False, msg="权限不足!")
            if log:
                handler.admin_log(request=request, uid=handler.get_current_user(), is_access=True)
            return func(*args, **kwargs)

        return wrapper

    return decorator

class HttpHelper(tornado.web.RequestHandler):
    def jsonify(self, *args, **kwargs):
        self.set_header("Content-Type", "text/json")
        indent = None
        separators = (",", ":")
        # if debug:  # 获取全局debug配置
        #     indent = 2
        #     separators = (", ", ": ")

        if args and kwargs:
            raise TypeError("jsonify() behavior undefined when passed both args and kwargs")
        elif len(args) == 1:  # single args are passed directly to dumps()
            data = args[0]
        else:
            data = args or kwargs
        self.write(json.dumps(data, indent=indent, separators=separators))

    def write_to_json(self, code=0, msg="", count=0, data=None):
        data = data if data else []
        ret = {"code": code, "msg": msg, "count": count if count else len(data), "data": data}
        self.write(json.dumps(ret))

    def success_api(self, msg: str = "成功"):
        """ 成功响应 默认值”成功“ """
        return self.jsonify(success=True, msg=msg)

    def fail_api(self, msg: str = "失败"):
        """ 失败响应 默认值“失败” """
        return self.jsonify(success=False, msg=msg)

    def table_api(self, msg: str = "", count=0, data=None, limit=10):
        """ 动态表格渲染响应 """
        res = {
            'msg': msg,
            'code': 0,
            'data': data,
            'count': count,
            'limit': limit
        }
        return self.jsonify(res)

    # def authorize(self, code=None):
    #     return authorize(code=code)

    def url_for(self, file_path=None, filename=None):
        if file_path == "static":
            # self.application.static_path
            filename = filename[1:] if filename[:1] == '/' else filename
            return self.static_url(filename)

    def get_template_namespace(self) -> Dict[str, Any]:
        namespace = super().get_template_namespace()
        # namespace.update({"url_for": self.url_for, "authorize": self.authorize})
        namespace.update({"url_for": self.url_for, "authorize": authorize})
        return namespace

    def login_log(self, uid, is_access):
        info = {
            'method': self.request.method,
            'url': self.request.path,
            'ip': self.request.remote_ip,
            'user_agent': xss_escape(self.request.headers.get('User-Agent')),
            # 'desc': xss_escape(request.get_argument('username', '')),
            'uid': uid,
            'success': int(is_access)
        }
        log = AdminLog(**info)
        session.add(log)
        session.flush()
        session.commit()
        return log.id

    def admin_log(self, request, uid, is_access):
        info = {
            'method': request.method,
            'url': request.path,
            'ip': request.remote_ip,
            'user_agent': xss_escape(request.headers.get('User-Agent')),
            'desc': request.body,
            'uid': uid,
            'success': int(is_access)
        }
        log = AdminLog(**info)
        session.add(log)
        session.commit()
        return log.id
